////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   ActionMethodDispatcher.java
// AUTHOR           :   ric.yik
// DATE CREATE      :   Feb 10, 2006
// DESCRIPTION      :   
//                  :   
//                  :   
//                  :   
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// Feb 10, 2006      ric.yik         1.0                 source is created.
//
//
//
////////////////////////////////////////////////////////////////////////////////

package com.erp.common.web;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import com.erp.framework.util.CommonUtil;
import com.erp.framework.util.logger.Logger;

/**
 * Dispatches a pageEvent to the corresponding processAction&lt;&lt;PageEvent&gt;&gt; method in an Action class. 
 * This classes eliminates the need of using a set of if-else statements on choosing the pageEvent 
 * process method in the action class.
 * 
 * <pre>
 * Sample usage:
 * 
 * class SampleAction extends SimpleMaintStyleAction {
 *     public ActionForward handlePageEvent(ActionMapping mapping, ActionForm formIn, 
 *             HttpServletRequest request, HttpServletResponse response, ActionErrors errors) {
 *         ActionForward actionForward = new ActionForward(mapping.getInput());
 *         MyModuleMaintenanceForm form = (MyModuleMaintenanceForm) formIn;
 *         if (this.isHandled(request)) {
 *             return actionForward;
 *         }
 *         ActionMethodDispatcher dispatcher = new ActionMethodDispatcher();
 *         dispatcher.setAction(this)
 *         dispatcher.setDefaultActionForward(actionForward);
 *         dispatcher.processAction(form.getPageEvent(), mapping, request, response, errors);
 *         this.saveToken(request);
 *         this.setHandled(request);
 *         return actionForward;
 *     }
 * 
 *     public ActionForward processActionSelectCustomer(ActionMapping mapping, ActionForm formIn, 
 *             HttpServletRequest request, HttpServletResponse response, ActionErrors errors) {
 *         // ...
 *     }
 * }
 * 
 * If form.getPageEvent() equals "selectCustomer", processActionSelectCustomer will be invoked.
 * </pre>
 * 
 * @author Ric Yik
 */
public class ActionMethodDispatcher extends SimpleBaseActionDispatcher {

    protected String getActionMethodName(String pageEvent) {
        String p = (this.isProcessStatus()) ? this.getStatus() : pageEvent;
        return (this.isProcessStatus() ? "processStatus" : "processAction") + ((p.length() > 1) ? p.substring(0, 1).toUpperCase() + p.substring(1) : p.substring(0, 1).toUpperCase());
    }

    /**
     * Invokes this.getAction().processAction<<pageEvent>>(mapping, request, response, errors).
     *
     * @param pageEvent
     * @param mapping
     * @param formIn
     * @param request
     * @param response
     * @param errors
     * @return
     */
    public ActionForward processAction(String pageEvent, ActionMapping mapping, ActionForm formIn, 
            HttpServletRequest request, HttpServletResponse response, ActionErrors errors) {
        if (this.getDefaultActionForward() == null) {
            this.setDefaultActionForward(new ActionForward(mapping.getInput()));
        }
        ActionForward actionForward = this.getDefaultActionForward();
        try {
            Class[] processActionParamClass = new Class[] { ActionMapping.class, ActionForm.class, HttpServletRequest.class, HttpServletResponse.class, ActionErrors.class };
            Class[] processStatusParamClass = new Class[] { ActionMapping.class, ActionForm.class, HttpServletRequest.class, HttpServletResponse.class, ActionErrors.class, String.class };
            Method actionMethod = this.getAction().getClass().getMethod(this.getActionMethodName(pageEvent), (this.isProcessStatus() ? processStatusParamClass : processActionParamClass));
            Object[] processActionParam = new Object[] { mapping, formIn, request, response, errors };
            Object[] processStatusParam = new Object[] { mapping, formIn, request, response, errors, this.getStatus() };
            actionForward = (ActionForward) actionMethod.invoke(this.getAction(), (this.isProcessStatus() ? processStatusParam : processActionParam));
        } catch (SecurityException e) {
            Logger.logExceptions(this.getAction(), e);
        } catch (NoSuchMethodException e) {
            actionForward = this.processWithNextDispatcher(pageEvent, mapping, formIn, request, response, errors);
        } catch (IllegalArgumentException e) {
            Logger.logExceptions(this.getAction(), e);
        } catch (IllegalAccessException e) {
            Logger.logExceptions(this.getAction(), e);
        } catch (InvocationTargetException e) {
            Logger.logExceptions(this.getAction(), CommonUtil.getTargetExecption(e));
        }
        return actionForward;
    }

}
